package org.m2acsi.entities;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import javax.validation.constraints.Size;
import org.m2acsi.utils.annotations.Email;

@Entity(name = "Users")
@Table(uniqueConstraints = {
    @UniqueConstraint(columnNames = "EMAIL")})
public class User implements Serializable {

    private Long id;
    private String firstname;
    private String lastname;
    private String email;
    private String password;
    private RoleType roleName;
    private List<Consultation> consultations;
    private List<Task> author;
    private List<Task> contributions;
    private List<Message> messages;
    private List<Opinion> opinions;
    private List<Upload> uploads;
    private List<Download> downloads;
    private Date creationDate;

    public User() {
        this.creationDate = new Date();
        this.roleName = RoleType.USER;
        this.consultations = new ArrayList<>();
        this.contributions = new ArrayList<>();
        this.messages = new ArrayList<>();
        this.opinions = new ArrayList<>();
        this.uploads = new ArrayList<>();
        this.downloads = new ArrayList<>();
    }

    public User(String firstName, String lastName, String email, String password) {
        this();
        this.firstname = firstName;
        this.lastname = lastName;
        this.email = email;
        this.password = password;
    }

    public User(String firstName, String lastName, String email, String password, RoleType role) {
        this(firstName, lastName, email, password);
        this.roleName = role;
        if (role == RoleType.ADMIN) {
            this.author = new ArrayList<>();
        }
    }

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Size(min = 1, max = 50)
    @Column(nullable = false, length = 50)
    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    @Size(min = 1, max = 50)
    @Column(nullable = false, length = 50)
    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @Email
    @Size(min = 5, max = 100)
    @Column(nullable = false, length = 100)
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Size(min = 6, max = 65)
    @Column(nullable = false, length = 65)
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Enumerated(EnumType.STRING)
    public RoleType getRoleName() {
        return roleName;
    }

    public void setRoleName(RoleType roleName) {
        this.roleName = roleName;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    public List<Consultation> getConsultations() {
        return consultations;
    }

    public void setConsultations(List<Consultation> consultations) {
        this.consultations = consultations;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "author")
    public List<Task> getAuthor() {
        return author;
    }

    public void setAuthor(List<Task> author) {
        this.author = author;
    }

    @ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinTable(name = "Contributions", joinColumns = {
        @JoinColumn(name = "USER_ID", nullable = false, updatable = false)}, inverseJoinColumns = {
        @JoinColumn(name = "TASK_ID", nullable = false, updatable = false)})
    public List<Task> getContributions() {
        return contributions;
    }

    public void setContributions(List<Task> contributions) {
        this.contributions = contributions;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    public List<Message> getMessages() {
        return messages;
    }

    public void setMessages(List<Message> messages) {
        this.messages = messages;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    public List<Opinion> getOpinions() {
        return opinions;
    }

    public void setOpinions(List<Opinion> opinions) {
        this.opinions = opinions;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "uploader")
    public List<Upload> getUploads() {
        return uploads;
    }

    public void setUploads(List<Upload> uploads) {
        this.uploads = uploads;
    }

    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "user")
    public List<Download> getDownloads() {
        return downloads;
    }

    public void setDownloads(List<Download> downloads) {
        this.downloads = downloads;
    }

    @Temporal(TemporalType.DATE)
    @Column(nullable = false, updatable = false)
    public Date getCreationDate() {
        return creationDate;
    }

    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + id + ", firstname=" + firstname + ", lastname=" + lastname + ", email=" + email + ", author=" + author + ", contributions=" + contributions + ", uploads=" + uploads + '}';
    }

}
